﻿// Decompiled with JetBrains decompiler
// Type: TaleWorlds.CampaignSystem.CraftingSystem.CraftingOrder
// Assembly: TaleWorlds.CampaignSystem, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: E85F8C15-4DF6-4E9C-A58A-29177E40D07A
// Assembly location: D:\steam\steamapps\common\Mount & Blade II Bannerlord\bin\Win64_Shipping_Client\TaleWorlds.CampaignSystem.dll

using System;
using System.Collections.Generic;
using System.Linq;
using TaleWorlds.CampaignSystem.CampaignBehaviors;
using TaleWorlds.Core;
using TaleWorlds.Library;
using TaleWorlds.Localization;
using TaleWorlds.SaveSystem;

#nullable disable
namespace TaleWorlds.CampaignSystem.CraftingSystem
{
  public class CraftingOrder : ITrackableCampaignObject, ITrackableBase
  {
    private const string TwoHandedSwordCraftingTemplateId = "TwoHandedSword";
    private const string DaggerCraftingTemplateId = "Dagger";
    private const string ThrowingKnifeCraftingTemplateId = "ThrowingKnife";
    private const string TwoHandedAxeCraftingTemplateId = "TwoHandedAxe";
    private const string ThrowingAxeCraftingTemplateId = "ThrowingAxe";
    private const string TwoHandedPolearmCraftingTemplateId = "TwoHandedPolearm";
    private const string JavelinCraftingTemplateId = "Javelin";
    private const string TwoHandedPolearmUsageCouchableId = "TwoHandedPolearm_Couchable";
    private const string TwoHandedPolearmUsageBracingId = "TwoHandedPolearm_Bracing";
    private const int CraftingAttemptDifficultyGap = 50;
    [SaveableField(10)]
    public readonly int BaseGoldReward;
    [SaveableField(20)]
    public readonly float OrderDifficulty;
    [SaveableField(30)]
    private readonly WeaponDesign _weaponDesignTemplate;
    [SaveableField(40)]
    public ItemObject PreCraftedWeaponDesignItem;
    [SaveableField(50)]
    private readonly CraftingCampaignBehavior.CraftedItemInitializationData _preCraftedWeaponDesignItemData;
    [SaveableField(60)]
    public Hero OrderOwner;
    [SaveableField(70)]
    public readonly int DifficultyLevel;

    internal static void AutoGeneratedStaticCollectObjectsCraftingOrder(
      object o,
      List<object> collectedObjects)
    {
      ((CraftingOrder) o).AutoGeneratedInstanceCollectObjects(collectedObjects);
    }

    protected virtual void AutoGeneratedInstanceCollectObjects(List<object> collectedObjects)
    {
      collectedObjects.Add((object) this.PreCraftedWeaponDesignItem);
      collectedObjects.Add((object) this.OrderOwner);
      collectedObjects.Add((object) this._weaponDesignTemplate);
      collectedObjects.Add((object) this._preCraftedWeaponDesignItemData);
    }

    internal static object AutoGeneratedGetMemberValueBaseGoldReward(object o)
    {
      return (object) ((CraftingOrder) o).BaseGoldReward;
    }

    internal static object AutoGeneratedGetMemberValueOrderDifficulty(object o)
    {
      return (object) ((CraftingOrder) o).OrderDifficulty;
    }

    internal static object AutoGeneratedGetMemberValuePreCraftedWeaponDesignItem(object o)
    {
      return (object) ((CraftingOrder) o).PreCraftedWeaponDesignItem;
    }

    internal static object AutoGeneratedGetMemberValueOrderOwner(object o)
    {
      return (object) ((CraftingOrder) o).OrderOwner;
    }

    internal static object AutoGeneratedGetMemberValueDifficultyLevel(object o)
    {
      return (object) ((CraftingOrder) o).DifficultyLevel;
    }

    internal static object AutoGeneratedGetMemberValue_weaponDesignTemplate(object o)
    {
      return (object) ((CraftingOrder) o)._weaponDesignTemplate;
    }

    internal static object AutoGeneratedGetMemberValue_preCraftedWeaponDesignItemData(object o)
    {
      return (object) ((CraftingOrder) o)._preCraftedWeaponDesignItemData;
    }

    public bool IsLordOrder => this.OrderOwner.IsLord;

    public CraftingOrder(
      Hero orderOwner,
      float orderDifficulty,
      WeaponDesign weaponDesignTemplate,
      CraftingTemplate template,
      int difficultyLevel = -1)
    {
      this.OrderOwner = orderOwner;
      this.OrderDifficulty = orderDifficulty;
      this.DifficultyLevel = difficultyLevel;
      this._weaponDesignTemplate = weaponDesignTemplate;
      Crafting.GenerateItem(weaponDesignTemplate, TextObject.Empty, (BasicCultureObject) orderOwner.Culture, template.ItemModifierGroup, ref this.PreCraftedWeaponDesignItem);
      if (this.PreCraftedWeaponDesignItem == null)
        this.PreCraftedWeaponDesignItem = DefaultItems.Trash;
      this._preCraftedWeaponDesignItemData = new CraftingCampaignBehavior.CraftedItemInitializationData(weaponDesignTemplate, this.PreCraftedWeaponDesignItem.Name, orderOwner.Culture);
      int maxItemMarketValue = Campaign.Current.Models.TradeItemPriceFactorModel.GetTheoreticalMaxItemMarketValue(this.PreCraftedWeaponDesignItem);
      this.BaseGoldReward = (int) ((double) maxItemMarketValue + (double) maxItemMarketValue * (double) MBRandom.RandomFloatRanged(-0.1f, 0.1f));
    }

    public void InitializeCraftingOrderOnLoad()
    {
      this.PreCraftedWeaponDesignItem = Crafting.InitializePreCraftedWeaponOnLoad(this.PreCraftedWeaponDesignItem, this._preCraftedWeaponDesignItemData.CraftedData, this._preCraftedWeaponDesignItemData.ItemName, (BasicCultureObject) this._preCraftedWeaponDesignItemData.Culture);
      if (this.PreCraftedWeaponDesignItem == null)
        return;
      this.PreCraftedWeaponDesignItem.IsReady = true;
    }

    public bool IsPreCraftedWeaponDesignValid()
    {
      if (this._preCraftedWeaponDesignItemData.CraftedData.Template.BuildOrders == null)
        return false;
      foreach (PieceData buildOrder in this._preCraftedWeaponDesignItemData.CraftedData.Template.BuildOrders)
      {
        bool flag = false;
        foreach (WeaponDesignElement usedPiece in this._preCraftedWeaponDesignItemData.CraftedData.UsedPieces)
        {
          if (buildOrder.PieceType == usedPiece.CraftingPiece.PieceType && usedPiece.IsValid)
            flag = true;
        }
        if (!flag)
          return false;
      }
      return true;
    }

    public WeaponComponentData GetStatWeapon()
    {
      if (this.PreCraftedWeaponDesignItem.Weapons.Count > 1)
      {
        string stringId = this.PreCraftedWeaponDesignItem.WeaponDesign.Template.StringId;
        string source = "";
        switch (stringId)
        {
          case "TwoHandedSword":
            source = "TwoHandedSword";
            break;
          case "Dagger":
            source = "Dagger";
            break;
          case "ThrowingKnife":
            source = "ThrowingKnife";
            break;
          case "TwoHandedAxe":
            source = "TwoHandedAxe";
            break;
          case "ThrowingAxe":
            source = "ThrowingAxe";
            break;
          case "TwoHandedPolearm":
            source = "TwoHandedPolearm";
            break;
          case "Javelin":
            source = "Javelin";
            break;
        }
        if (!source.IsEmpty<char>())
        {
          foreach (WeaponComponentData weapon in (List<WeaponComponentData>) this.PreCraftedWeaponDesignItem.Weapons)
          {
            if (weapon.WeaponDescriptionId == source || source == "TwoHandedPolearm" && (weapon.WeaponDescriptionId == "TwoHandedPolearm_Couchable" || weapon.WeaponDescriptionId == "TwoHandedPolearm_Bracing"))
              return weapon;
          }
        }
      }
      return this.PreCraftedWeaponDesignItem.PrimaryWeapon;
    }

    public bool IsOrderAvailableForHero(Hero hero)
    {
      return (double) (hero.GetSkillValue(DefaultSkills.Crafting) + 50) >= (double) this.OrderDifficulty;
    }

    public bool CanHeroCompleteOrder(Hero hero, ItemObject craftDesignItem) => true;

    public float GetOrderExperience(ItemObject craftedItem, ItemModifier itemModifier)
    {
      int num1 = (int) (this.PreCraftedWeaponDesignItem.Tier + 1);
      float num2 = MathF.Clamp(MathF.Pow(3f, (float) (craftedItem.Tier + 1 - num1)), 0.0f, 1f);
      float orderExperience = (float) Campaign.Current.Models.TradeItemPriceFactorModel.GetTheoreticalMaxItemMarketValue(this.PreCraftedWeaponDesignItem) * 0.25f;
      float craftedStatsSum;
      float requiredStatsSum;
      bool thrustDamageCheck;
      bool swingDamageCheck;
      this.CheckForBonusesAndPenalties(craftedItem, itemModifier, out craftedStatsSum, out requiredStatsSum, out thrustDamageCheck, out swingDamageCheck);
      if ((double) craftedStatsSum < (double) requiredStatsSum || !thrustDamageCheck || !swingDamageCheck)
        orderExperience = orderExperience * 0.5f * num2;
      return orderExperience;
    }

    public void CheckForBonusesAndPenalties(
      ItemObject craftedItem,
      ItemModifier itemModifier,
      out float craftedStatsSum,
      out float requiredStatsSum,
      out bool thrustDamageCheck,
      out bool swingDamageCheck)
    {
      WeaponComponentData weapon1;
      List<CraftingStatData> statDataForItem = this.GetStatDataForItem(this.PreCraftedWeaponDesignItem, out weapon1);
      WeaponComponentData weapon2;
      List<CraftingStatData> source = this.GetStatDataForItem(craftedItem, out weapon2);
      swingDamageCheck = true;
      thrustDamageCheck = true;
      if (weapon1.SwingDamageType != DamageTypes.Invalid && weapon1.SwingDamageType != weapon2.SwingDamageType)
        swingDamageCheck = false;
      if (weapon1.ThrustDamageType != DamageTypes.Invalid && weapon1.ThrustDamageType != weapon2.ThrustDamageType)
        thrustDamageCheck = false;
      requiredStatsSum = 0.0f;
      craftedStatsSum = 0.0f;
      if (itemModifier != null)
      {
        List<CraftingStatData> craftingStatDataList = new List<CraftingStatData>();
        foreach (CraftingStatData craftingStatData in source)
        {
          float curValue = craftingStatData.CurValue;
          if (craftingStatData.Type == CraftingTemplate.CraftingStatTypes.SwingDamage)
            curValue = (float) itemModifier.ModifyDamage((int) craftingStatData.CurValue);
          else if (craftingStatData.Type == CraftingTemplate.CraftingStatTypes.SwingSpeed)
            curValue = (float) itemModifier.ModifySpeed((int) craftingStatData.CurValue);
          else if (craftingStatData.Type == CraftingTemplate.CraftingStatTypes.ThrustDamage)
            curValue = (float) itemModifier.ModifyDamage((int) craftingStatData.CurValue);
          else if (craftingStatData.Type == CraftingTemplate.CraftingStatTypes.ThrustSpeed)
            curValue = (float) itemModifier.ModifySpeed((int) craftingStatData.CurValue);
          else if (craftingStatData.Type == CraftingTemplate.CraftingStatTypes.Handling)
            curValue = (float) itemModifier.ModifySpeed((int) craftingStatData.CurValue);
          craftingStatDataList.Add(new CraftingStatData(craftingStatData.DescriptionText, curValue, craftingStatData.MaxValue, craftingStatData.Type, craftingStatData.DamageType));
        }
        source = craftingStatDataList;
      }
      foreach (CraftingStatData craftingStatData1 in statDataForItem)
      {
        CraftingStatData orderStat = craftingStatData1;
        if (orderStat.IsValid)
        {
          CraftingStatData craftingStatData2 = source.FirstOrDefault<CraftingStatData>((Func<CraftingStatData, bool>) (x => x.Type == orderStat.Type));
          if ((double) craftingStatData2.CurValue != (double) orderStat.CurValue)
          {
            requiredStatsSum += orderStat.CurValue;
            craftedStatsSum += craftingStatData2.CurValue;
          }
        }
      }
    }

    public List<CraftingStatData> GetStatDataForItem(
      ItemObject itemObject,
      out WeaponComponentData weapon)
    {
      List<CraftingStatData> statDataForItem = new List<CraftingStatData>();
      weapon = (WeaponComponentData) null;
      WeaponComponentData statWeapon = this.GetStatWeapon();
      int usageIndex = -1;
      for (int index = 0; index < itemObject.Weapons.Count; ++index)
      {
        if (statWeapon.WeaponDescriptionId == itemObject.Weapons[index].WeaponDescriptionId)
        {
          weapon = itemObject.Weapons[index];
          usageIndex = index;
          break;
        }
      }
      if (weapon == null && this.PreCraftedWeaponDesignItem.Weapons.Count > 1)
      {
        for (int index = 0; index < this.PreCraftedWeaponDesignItem.Weapons.Count; ++index)
        {
          if (itemObject.PrimaryWeapon.WeaponDescriptionId == this.PreCraftedWeaponDesignItem.Weapons[index].WeaponDescriptionId)
          {
            weapon = itemObject.PrimaryWeapon;
            usageIndex = 1;
            break;
          }
        }
      }
      bool flag1 = weapon.ThrustDamageType != DamageTypes.Invalid;
      bool flag2 = weapon.SwingDamageType != DamageTypes.Invalid;
      foreach (KeyValuePair<CraftingTemplate.CraftingStatTypes, float> statData in itemObject.WeaponDesign.Template.GetStatDatas(usageIndex, weapon.ThrustDamageType, weapon.SwingDamageType))
      {
        TextObject text1 = GameTexts.FindText("str_crafting_stat", statData.Key.ToString());
        int num;
        if (statData.Key == CraftingTemplate.CraftingStatTypes.ThrustSpeed & flag1)
          statDataForItem.Add(new CraftingStatData(text1, (float) weapon.ThrustSpeed, statData.Value, statData.Key));
        else if (statData.Key == CraftingTemplate.CraftingStatTypes.SwingSpeed & flag2)
          statDataForItem.Add(new CraftingStatData(text1, (float) weapon.SwingSpeed, statData.Value, statData.Key));
        else if (statData.Key == CraftingTemplate.CraftingStatTypes.ThrustDamage & flag1)
        {
          TextObject textObject = text1;
          num = (int) weapon.ThrustDamageType;
          TextObject text2 = GameTexts.FindText("str_inventory_dmg_type", num.ToString());
          textObject.SetTextVariable("THRUST_DAMAGE_TYPE", text2);
          statDataForItem.Add(new CraftingStatData(text1, (float) weapon.ThrustDamage, statData.Value, statData.Key, weapon.ThrustDamageType));
        }
        else if (statData.Key == CraftingTemplate.CraftingStatTypes.SwingDamage & flag2)
        {
          TextObject textObject = text1;
          num = (int) weapon.SwingDamageType;
          TextObject text3 = GameTexts.FindText("str_inventory_dmg_type", num.ToString());
          textObject.SetTextVariable("SWING_DAMAGE_TYPE", text3);
          statDataForItem.Add(new CraftingStatData(text1, (float) weapon.SwingDamage, statData.Value, statData.Key, weapon.SwingDamageType));
        }
        else if (statData.Key == CraftingTemplate.CraftingStatTypes.Handling)
          statDataForItem.Add(new CraftingStatData(text1, (float) weapon.Handling, statData.Value, statData.Key));
        else if (statData.Key == CraftingTemplate.CraftingStatTypes.MissileDamage)
        {
          DamageTypes damageType = DamageTypes.Invalid;
          if (weapon.ThrustDamageType != DamageTypes.Invalid)
          {
            damageType = weapon.ThrustDamageType;
            TextObject textObject = text1;
            num = (int) weapon.ThrustDamageType;
            TextObject text4 = GameTexts.FindText("str_inventory_dmg_type", num.ToString());
            textObject.SetTextVariable("THRUST_DAMAGE_TYPE", text4);
          }
          else if (weapon.SwingDamageType != DamageTypes.Invalid)
          {
            damageType = weapon.SwingDamageType;
            TextObject textObject = text1;
            num = (int) weapon.SwingDamageType;
            TextObject text5 = GameTexts.FindText("str_inventory_dmg_type", num.ToString());
            textObject.SetTextVariable("SWING_DAMAGE_TYPE", text5);
          }
          else
            Debug.FailedAssert("Missile damage type is missing.", "C:\\Develop\\MB3\\Source\\Bannerlord\\TaleWorlds.CampaignSystem\\CraftingSystem\\CraftingOrder.cs", nameof (GetStatDataForItem), 365);
          statDataForItem.Add(new CraftingStatData(text1, (float) weapon.MissileDamage, statData.Value, statData.Key, damageType));
        }
        else if (statData.Key == CraftingTemplate.CraftingStatTypes.MissileSpeed)
          statDataForItem.Add(new CraftingStatData(text1, (float) weapon.MissileSpeed, statData.Value, statData.Key));
        else if (statWeapon.IsRangedWeapon && statData.Key == CraftingTemplate.CraftingStatTypes.Accuracy)
          statDataForItem.Add(new CraftingStatData(text1, (float) weapon.Accuracy, statData.Value, statData.Key));
        else if (statData.Key == CraftingTemplate.CraftingStatTypes.WeaponReach)
          statDataForItem.Add(new CraftingStatData(text1, (float) weapon.WeaponLength, statData.Value, statData.Key));
      }
      return statDataForItem;
    }

    public TextObject GetName() => this.PreCraftedWeaponDesignItem.Name;

    public Vec3 GetPosition()
    {
      float height = 0.0f;
      Campaign.Current.MapSceneWrapper.GetHeightAtPoint(this.OrderOwner.CurrentSettlement.Position2D, ref height);
      return new Vec3(this.OrderOwner.CurrentSettlement.Position2D.x, this.OrderOwner.CurrentSettlement.Position2D.y, height);
    }

    public float GetTrackDistanceToMainAgent()
    {
      return this.GetPosition().Distance(Hero.MainHero.GetPosition());
    }

    public bool CheckTracked(BasicCharacterObject basicCharacter) => false;
  }
}
